#define LOG_TAG "bms.can"
#include "elog.h"

#include "utils.h"
#include "bms_can.h"
#include "power_can.h"

#include "cmd_map_rw.h"
#include "charge_mem_tab.h"

#include <stdint.h>
#include <string.h>

bms_t *get_bms_struct(void);
/**
 * @brief                   SAEJ1939的接收数据回调函数
 * @param  info             SAEJ1939的仲裁段结构
 * @param  data             接收数据
 * @param  length           数据长度
 */
void can_ch0_recv_callback(const j1939_msg_info_t *info, const uint8_t *data, uint32_t length)
{
    qmsg_t qmsg = {0};
    bms_t *bms = get_bms_struct();
    memcpy((uint8_t *)&qmsg.j1939_bms, (uint8_t *)info, sizeof(j1939_msg_info_t));
    memcpy((uint8_t *)qmsg.data.buf, data, length);
    qmsg.data.len = length;
    if (bms->app_q != NULL)
    {
        xQueueSend(bms->app_q, &qmsg, 0);
        log_d("type %04x - %04x --> %04x | PGN %04x - len %d", info->addr.type, info->addr.sa, info->addr.da, info->addr.pgn, length);        
    }
}

/**
 * @brief  BMS的初始化
 * @return int 
 */
int bms_init(void)
{
    int ret = 0;
    bms_t *bms = get_bms_struct();

    bms->app_q = xQueueCreate(10, sizeof(qmsg_t));
    if (bms->app_q == NULL)
    {
        log_e("bms queue create fail.");
    }
    configASSERT(bms->app_q);
    return ret;
}

/**
 * @brief  发送充电桩和BMS的握手报文 充电机 ---> BMS
 * @return int 
 */
int charge_send_chm(void)
{
    int ret = 0;
    j1939_msg_info_t msg = {
        .addr = {
            .sa = CHARGE_CAN_ADDR,
            .da = BMS_CAN_ADDR,
            .pgn = CHARGE_CHM_PGN},
        .priority = 6,
    };
    uint8_t buffer[3] = {0};

    buffer[0] = (uint8_t)CHARGE_CAN_VERSION;
    buffer[1] = (uint8_t)CHARGE_CAN_VERSION >> 8;
    buffer[2] = (uint8_t)CHARGE_CAN_VERSION >> 16;
    ret = j1939tp_transmit(get_runtime(), &msg, buffer, sizeof(buffer));
    log_d("send CHM message ret %d", ret);
    return ret;
}

/**
 * @brief                   充电桩的CRM报文
 * @param  result           回复BMS的结果
 * @return int 
 */
int charge_send_crm(int result)
{
    int ret = 0;
    uint32_t number = CHARGE_NUMBER;   /* 充电机编号 */
    uint32_t sanc = CHARGE_NUMBER;     /* 区域编码 */
    j1939_msg_info_t msg = {
        .addr = {
            .sa = CHARGE_CAN_ADDR,
            .da = BMS_CAN_ADDR,
            .pgn = CHARGE_CRM_PGN},
        .priority = 6,
    };
    uint8_t buffer[8] = {0};

    buffer[0] = result;
    memcpy((uint8_t *)&buffer[1], (uint8_t *)&number, 4);
    memcpy((uint8_t *)&buffer[5], (uint8_t *)&sanc, 3);
    ret = j1939tp_transmit(get_runtime(), &msg, buffer, sizeof(buffer));
    log_d("send CRM message ret %d", ret);
    return ret;
}

/**
 * @brief  向BMS发送时间信息 格式：年/月/日/时/分/秒
 * @return int 
 */
int charge_send_cts(void)
{
    int ret = 0;
    j1939_msg_info_t msg = {
        .addr = {
            .sa = CHARGE_CAN_ADDR,
            .da = BMS_CAN_ADDR,
            .pgn = CHARGE_CTS_PGN},
        .priority = 6,
    };
    uint8_t buffer[8] = {0};

    buffer[0] = 0x56;
    buffer[1] = 0x43;
    buffer[2] = 0x06;
    buffer[3] = 0x07;
    buffer[4] = 0x08;
    buffer[5] = 0x02;
    buffer[6] = 0x06;
    general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_UTC_TIME, buffer, sizeof(buffer));

    ret = j1939tp_transmit(get_runtime(), &msg, buffer, 7);
    log_d("send CTS message ret %d", ret);
    return ret;
}

/**
 * @brief  充电桩的CML报文
 * @return int 
 */
int charge_send_cml(void)
{
    int ret = 0;
    j1939_msg_info_t msg = {
        .addr = {
            .sa = CHARGE_CAN_ADDR,
            .da = BMS_CAN_ADDR,
            .pgn = CHARGE_CML_PGN},
        .priority = 6,
    };
    cml_msg_t cml_msg = {0};
    
    cml_msg.data.max_vol  = PWR_MAX_OUT_VOL;
    cml_msg.data.min_vol  = PWR_MIN_OUT_VOL;
    cml_msg.data.max_curr = PWR_MAX_OUT_CURR;
    cml_msg.data.min_curr = PWR_MIN_OUT_CURR;
    /* 充电机的最大输出能力， 最大输出电压，最大输出电流，最低输出电流 */
    ret = j1939tp_transmit(get_runtime(), &msg, cml_msg.buf, sizeof(cml_msg.buf));
    log_d("send CTS message ret %d", ret);
    return ret;
}

/**
 * @brief                   充电桩的CRO报文
 * @param  result           回复BMS的结果
 * @return int 
 */
int charge_send_cro(int result)
{
    int ret = 0;
    j1939_msg_info_t msg = {
        .addr = {
            .sa = CHARGE_CAN_ADDR,
            .da = BMS_CAN_ADDR,
            .pgn = CHARGE_CRO_PGN},
        .priority = 4,
    };
    uint8_t buffer[8] = {0};

    buffer[0] = result;
    ret = j1939tp_transmit(get_runtime(), &msg, buffer, sizeof(buffer));
    log_d("send CRO message ret %d", ret);
    return ret;
}

/**
 * @brief  充电桩的CST报文
 * @return int 
 */
int charge_send_cst(uint32_t cst)
{
    int ret = 0;
    j1939_msg_info_t msg = {
        .addr = {
            .sa = CHARGE_CAN_ADDR,
            .da = BMS_CAN_ADDR,
            .pgn = CHARGE_CST_PGN},
        .priority = 4,
    };
    cst_msg_t cst_msg = {0};

    memcpy(cst_msg.buf, (uint8_t *)&cst, sizeof(cst_msg.buf));
    log_d("send cst data %04x", cst);
    ret = j1939tp_transmit(get_runtime(), &msg, cst_msg.buf, sizeof(cst_msg.buf));
    log_d("send CST message ret %d", ret);
    return ret;
}

/**
 * @brief  充电桩的CSD报文
 * @return int 
 */
int charge_send_csd(void)
{
    int ret = 0;
    j1939_msg_info_t msg = {
        .addr = {
            .sa = CHARGE_CAN_ADDR,
            .da = BMS_CAN_ADDR,
            .pgn = CHARGE_CSD_PGN},
        .priority = 6,
    };
    csd_msg_t csd_msg = {0};
    uint32_t charge_time = 0;

    general_cmd_map_get(CMD_MAP_CHARGE, ONCE_CHARGE_TIME, (uint8_t *)&charge_time, 4u);
    csd_msg.time_sum    = charge_time;
    csd_msg.out_kwh     = 0;
    csd_msg.charge_num  = CHARGE_NUMBER;
    ret = j1939tp_transmit(get_runtime(), &msg, csd_msg.buf, sizeof(csd_msg.buf));
    log_d("send CSD message ret %d", ret);
    return ret;
}

/**
 * @brief                   充电桩的CCS报文
 * @param  vol              充电桩的输出电压
 * @param  curr             充电桩的输出电流
 * @param  time             累计充电时间
 * @return int 
 */
int charge_send_ccs(uint32_t vol, uint32_t curr, uint32_t time)
{
    int ret = 0;
    j1939_msg_info_t msg = {
        .addr = {
            .sa = CHARGE_CAN_ADDR,
            .da = BMS_CAN_ADDR,
            .pgn = CHARGE_CCS_PGN},
        .priority = 6,
    };
    ccs_msg_t ccs_msg = {0};
    
    /* 电源模块的输出电压和电流 */
    ccs_msg.data.out_vol =  PHY_TO_SIGNAL(3, h_to_f(vol), 0, 0.1f);                             /* 电压精度0.1 */
    ccs_msg.data.out_curr = PHY_TO_SIGNAL(1, (float)(0.0f - h_to_f(curr)), -400, 0.1f);         /* 电流精度0.1，偏移量-400A */
    ccs_msg.data.sum_time = time;
    ccs_msg.data.charge_en = pdTRUE;
    ret = j1939tp_transmit(get_runtime(), &msg, ccs_msg.buf, sizeof(ccs_msg.buf));
    log_d("send CCS message ret %d", ret);
    return ret;
}

/**
 * @brief  发送BEM报文
 * @return int 
 */
int charge_send_cem(void)
{
    int ret = 0;
    j1939_msg_info_t msg = {
        .addr = {
            .sa = CHARGE_CAN_ADDR,
            .da = BMS_CAN_ADDR,
            .pgn = CHARGE_CEM_PGN},
        .priority = 2,
    };
    cem_msg_t cem_msg = {0};
    undata32_t undata32 = {0};

    general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
    memcpy(undata32.data8, cem_msg.buf, 4);
    if (undata32.data32 != 0)
    {
        ret = j1939tp_transmit(get_runtime(), &msg, cem_msg.buf, sizeof(cem_msg.buf));
        log_d("send CEM message ret %d", ret);
    }
    return ret;
}

